home *** CD-ROM | disk | FTP | other *** search
/ The Fatted Calf / The Fatted Calf.iso / Applications / GraphicViewers / ViewGif2 / Source / Animator.m < prev    next >
Text File  |  1991-07-17  |  4KB  |  218 lines

  1.  
  2. /*
  3.  *  An 'Animator' controls the timing for your action method of choice.
  4.  *  The object may function as a general timer object; i.e.
  5.  *  graphics are neither expected nor required by the class.
  6.  *  When you create an Animator with +newChronon, you specify
  7.  *  the time interval between calls, the adaptation time constant (see below),
  8.  *  the target to which the method belongs, the action name, whether to 
  9.  *  automatically start up the timing upon creation, and an event mask (if you     
  10.  *  plan to break conditionally out of loops within the action method).
  11.  *
  12.  *  The Animator has adaptive means for adjusting to harsh operating
  13.  *  environments.  An adaptation constant d > 0. will invoke dynamical 
  14.  *  correction of entry times, on-the-fly, so that the desired chronon
  15.  *  will be realized in a real-time sense.
  16.  *
  17.  *  Functionality and applications are discussed in Report ETC-0008.
  18.  */
  19.  
  20. #import "Animator.h"
  21.  
  22. #import <appkit/Application.h>
  23. #import <sys/time.h>
  24. #import <objc/vectors.h>
  25.  
  26.  
  27. @implementation Animator
  28.  
  29. void timerFunction(teNum, now, self)
  30. DPSTimedEntry teNum;
  31. double now;
  32. Animator *self;
  33. {
  34.     gettimeofday(&self->entrytime, NULL);
  35.     if (self->howOften > 0.0) {
  36.     [self adapt];
  37.     }
  38.     
  39.     [self->target perform:self->action with:self];
  40. }
  41.  
  42. - initChronon:(double)dt    /* The time increment desired. */
  43.   adaptation:(double)howoft    /* Adaptive time constant (0.deactivates).*/
  44.   target:(id)targ        /* Target to whom proc belongs. */
  45.   action:(SEL)act        /* The action. */
  46.   autoStart:(int)start        /* Automatic start of timed entry? */
  47.   eventMask:(int)eMask        /* Mask for optional check in "shouldBreak". */
  48. {
  49.     [super init];
  50.     ticking = NO;
  51.     desireddt = dt;
  52.     [self setIncrement:dt];
  53.     [self setAdaptation:howoft];
  54.     [self setTarget:targ];
  55.     [self setAction:act];
  56.     
  57.     if (start) {
  58.     [self startEntry];
  59.     }
  60.     
  61.     mask = eMask;
  62.     [self resetRealTime];
  63.     
  64.     return self;
  65. }
  66.  
  67. - resetRealTime
  68. /* After this call, getDoubleRealTime is the real time that ensues. */
  69.     struct timeval    realtime;
  70.     
  71.     gettimeofday(&realtime, NULL);
  72.     synctime = realtime.tv_sec + realtime.tv_usec / 1000000.0;
  73.     passcounter = 0;
  74.     t0 = 0.0;
  75.     
  76.     return self;
  77. }
  78.  
  79. - (double)getSyncTime
  80. {
  81.     return synctime;
  82. }
  83.  
  84. - (double)getDoubleEntryTime
  85. /* Returns real time since "resetrealTime". */
  86. {
  87.     return (- synctime + entrytime.tv_sec + entrytime.tv_usec / 1000000.0);
  88. }
  89.  
  90. - (double)getDoubleRealTime
  91. /* Returns real time since "resetrealTime". */
  92. {
  93.     struct timeval    realtime;
  94.     struct timezone    tzone;
  95.     
  96.     gettimeofday(&realtime, &tzone);
  97.     return (- synctime + realtime.tv_sec + realtime.tv_usec / 1000000.0);
  98. }
  99.  
  100. - (double)getDouble
  101. {
  102.     return [self getDoubleRealTime];
  103. }
  104.  
  105. - adapt
  106. /* Adaptive time-step algorithm. */
  107. {
  108.     double t;
  109.     
  110.     if (!ticking) {
  111.     return self;
  112.     }
  113.     
  114.     ++passcounter;
  115.     t = [self getDoubleEntryTime];
  116.     
  117.     if (t - t0 >= howOften) {      
  118.     adapteddt *= desireddt * passcounter / (t - t0);
  119.     [self setIncrement:adapteddt];
  120.     [self startEntry];
  121.     passcounter = 0;
  122.     t0 = t;
  123.     }
  124.     return self;
  125. }
  126.   
  127. - setBreakMask:(int)eventMask
  128. {
  129.     mask = eventMask;
  130.     return self;
  131. }
  132.  
  133. - (int)getBreakMask
  134. {
  135.     return mask;
  136. }
  137.  
  138. - (int)isTicking
  139. {
  140.     return ticking;
  141. }
  142.    
  143. - (int)shouldBreak
  144. /* Call this to see if you want to exit a loop in your action method. */
  145. {
  146.     NXEvent    *e, event;
  147.     
  148.     e = [NXApp peekNextEvent:mask
  149.                into:&event
  150.            waitFor:0.0
  151.            threshold:NX_MODALRESPTHRESHOLD + 1];
  152.            
  153.     return (e ? 1: 0);
  154. }
  155.  
  156. - setIncrement:(double)dt
  157. {
  158.     adapteddt = dt;
  159.     interval = dt;
  160.   
  161.     return self;
  162. }
  163.  
  164. - (double)getIncrement
  165. {
  166.     return adapteddt;
  167. }
  168.  
  169. - setAdaptation:(double)oft
  170. {
  171.     howOften = oft;
  172.     return self;
  173. }
  174.  
  175. - setTarget:(id)targ
  176. {
  177.     target = targ;
  178.     return self;
  179. }
  180.  
  181. - setAction:(SEL)aSelector
  182. {
  183.     action = aSelector;
  184.     return self;
  185. }
  186.  
  187. - startEntry
  188.     [self stopEntry];
  189.     teNum = DPSAddTimedEntry(interval, &timerFunction, self,
  190.                      NX_MODALRESPTHRESHOLD+1);
  191.     ticking = YES;
  192.     
  193.     return self;
  194. }
  195.  
  196. - stopEntry
  197. {
  198.     if (ticking) {
  199.     DPSRemoveTimedEntry(teNum);
  200.     }
  201.     ticking = NO;
  202.     
  203.     return self;
  204. }
  205.  
  206. - free
  207. {
  208.     if (ticking) {
  209.     DPSRemoveTimedEntry(teNum);
  210.     }
  211.     
  212.     return [super free];
  213. }
  214.  
  215. @end    
  216.